package org.spring.boot.rabbitmq.conf;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * @author: eastcom
 * @desc: RabbitTemplate配置类
 **/
@Component
public class RabbitConfig {

	private static final Logger log = LoggerFactory.getLogger(RabbitConfig.class);

	/**
	 * 延迟队列(死信队列) TTL名称
	 */
	private static final String REGISTER_DELAY_QUEUE = "dev.book.register.delay.queue";

	/**
	 * DLX，dead letter发送到的 exchange，此处的 exchange 很重要,具体消息就是发送到该交换机的
	 */
	public static final String REGISTER_DELAY_EXCHANGE = "dev.book.register.delay.exchange";

	/**
	 * routing key 名称
	 * 此处的 routingKey 很重要要,具体消息发送在该 routingKey 的
	 */
	public static final String DELAY_ROUTING_KEY = "";

	/**
	 * 从私信队列转发后的队列
	 */
	public static final String REGISTER_QUEUE_NAME = "dev.book.register.queue";

	/**
	 * 从私信队列转发后的交换机
	 */
	public static final String REGISTER_EXCHANGE_NAME = "dev.book.register.exchange";

	/**
	 * 从私信队列转发后的routing_key
	 */
	public static final String ROUTING_KEY = "all";


	/**
	 * 初始化RabbitTemplate
	 * @param connectionFactory
	 * @return RabbitTemplate
	 */
	@Bean(name = "dlRabbitTemplate")
	public RabbitTemplate rabbitTemplate(CachingConnectionFactory connectionFactory) {
		connectionFactory.setPublisherConfirms(true);
		connectionFactory.setPublisherReturns(true);
		RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
		rabbitTemplate.setMandatory(true);
		rabbitTemplate.setConfirmCallback(
				new RabbitTemplate.ConfirmCallback(){

					@Override
					public void confirm(CorrelationData correlationData, boolean ack, String cause) {
						log.info("消息发送成功:correlationData({}),ack({}),cause({})", correlationData, ack, cause);
					}
				});
		rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
			@Override
			public void returnedMessage(Message exchange, int routingKey, String replyCode, String replyText, String message) {
				log.info("消息丢失:exchange({}),route({}),replyCode({}),replyText({}),message:{}", exchange, routingKey, replyCode, replyText, message);
			}
		});
		return rabbitTemplate;
	}


	/**
	 * 创建一个死信队列，同时声明该队列中的消息转发到哪个交换机上
	 * 规定转发时携带roting-key的名称
	 * @return 私信队列
	 */
	@Bean
	public Queue delayProcessQueue() {
		Map<String, Object> params = new HashMap<>(16);
		/* x-dead-letter-exchange 定义死信队列中的消息发送到哪个交换机中 */
		params.put("x-dead-letter-exchange", REGISTER_EXCHANGE_NAME);
		/* x-dead-letter-routing-key 定义了这些死信在转发时携带 routing-key 名称 */
		params.put("x-dead-letter-routing-key", ROUTING_KEY);
		/*队列名称，是否持久化，是否独有，是否自动删除，配置死信队列参数 */
		return new Queue(REGISTER_DELAY_QUEUE, true, false, false, params);
	}

	/**
	 * 定义一个点对点模式的交换机
	 * @return DirectExchange 点对点模式
	 */
	@Bean
	public DirectExchange delayExchange() {
		return new DirectExchange(REGISTER_DELAY_EXCHANGE);
	}

	/**
	 * 将Direct模式的交换机与队列进行绑定，并定义rotting-key
	 * @return Binding
	 */
	@Bean
	public Binding dlxBinding() {
		return BindingBuilder.bind(delayProcessQueue()).to(delayExchange()).with(DELAY_ROUTING_KEY);
	}


	/**
	 * 定义一个队列
	 * @return 队列
	 */
	@Bean
	public Queue registerBookQueue() {
		return new Queue(REGISTER_QUEUE_NAME, true);
	}

	/**
	 * 定义一个Topic模式的交换机
	 * @return TopicExchange
	 */
	@Bean
	public TopicExchange registerBookTopicExchange() {
		return new TopicExchange(REGISTER_EXCHANGE_NAME);
	}

	/**
	 * 将Topic模式的交换机与队列绑定，并定义routing-key
	 * @return Binding
	 */
	@Bean
	public Binding registerBookBinding() {
		// TODO 如果要让延迟队列之间有关联,这里的 routingKey 和 绑定的交换机很关键
		return BindingBuilder.bind(registerBookQueue()).to(registerBookTopicExchange()).with(ROUTING_KEY);
	}


}
